﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using XcoAppSpaces.Transport.Sockets;
using XcoAppSpaces.Contracts.Transport;
using System.Threading;
using XcoAppSpaces.Contracts.Logging;
using XcoAppSpaces.Serialization.Binary;
using System.Diagnostics;

namespace test.XcoAppSpaces.Transport.Sockets
{
	[TestFixture]
	public class PerformanceTest
	{

		public static void Main()
		{
			new PerformanceTest().TestPerformance();
		}

	
        private class SenderInfo
        {
            public int ID { get; set; }
            public int From { get; set; }
            public int To { get; set; }
            public string RemoteAddr { get; set; }
            public XcoTCPTransportService CommService { get; set; }
            public XcoBinarySerializer Serializer { get; set; }
         
        }

		[Test]
		public void TestPerformance()
		{
			XcoLoggerFactory.CreateInstance = (t => new TestLogger.TestLogger());

			XcoTCPTransportService comm1 = new XcoTCPTransportService(8003);
			XcoBinarySerializer ser1 = new XcoBinarySerializer();
			XcoTCPTransportService comm2 = new XcoTCPTransportService(8004);
			XcoBinarySerializer ser2 = new XcoBinarySerializer();
			//comm1.SetLogger(new TestLoggerFactory());
			//comm2.SetLogger(new TestLoggerFactory());
            ReceivedTmp received = new ReceivedTmp();
			try
			{
				comm1.OnMessageReceived += received.MessageReceived;
				comm2.OnMessageReceived += received.MessageReceived;
				
				comm1.SecuritySettings.AuthenticationKey = "test";
				comm2.SecuritySettings.AuthenticationKey = "test";

				comm1.Start();
				comm2.Start();
				string addr2 = Environment.MachineName.ToLower() + ":" + 8004;


				byte[] testBytes = ser1.Serialize(new IntMsg { value = 0, strValue1 = 0.ToString(), strValue2 = "test", msgPartList = null }); // new List<MsgPart> { new MsgPart { exValue = new Exception(), strValue = "bla" } } });
				Console.WriteLine("Approximate Message Length: " + testBytes.Length);

                byte[] context = new byte[] { 0, 1, 2, 3, 4, 5 };
               
                received.StopWatch.Start();
				int n = 50000;
				for (int i = 1; i <= n; i++)
				{
					//comm1.SendMessage(new IntMsg { RemoteAddress = addr2, IntValue = i });
                    byte[] bytes = ser1.Serialize(new IntMsg {  value = i, strValue1 = i.ToString(), strValue2 = "test", msgPartList = null }); // new List<MsgPart> { new MsgPart { exValue = new Exception(), strValue = "bla" } } });

                    comm1.Send(new XcoMessage { Content = bytes, CausalityContext = context }, addr2);
				}

                received.StopWatch.Stop();
                int speed = (int)( n / ((double)received.StopWatch.ElapsedMilliseconds / (double)1000));
                Console.WriteLine("Send finished: {0} @ {1} millisec: {2} per sec", n, received.StopWatch.ElapsedMilliseconds,speed);
                Thread.Sleep(1000);
                Assert.AreEqual(n, received.Counter);
				
			}
			catch (Exception ex)
			{
				Console.WriteLine("ERROR: " + ex);

			}
			finally
			{
				comm1.Stop();
				comm2.Stop();
			}

		}


        [Test]
        public void MultiSender()
        {
            XcoLoggerFactory.CreateInstance = (t => new TestLogger.TestLogger());

            XcoTCPTransportService comm1a = new XcoTCPTransportService(8003);
            XcoTCPTransportService comm1b = new XcoTCPTransportService(8005);
            XcoTCPTransportService comm1c = new XcoTCPTransportService(8006);
          
            XcoTCPTransportService comm2 = new XcoTCPTransportService(8004);
            XcoBinarySerializer ser = new XcoBinarySerializer();
            //comm1.SetLogger(new TestLoggerFactory());
            //comm2.SetLogger(new TestLoggerFactory());
            ReceivedTmp received = new ReceivedTmp();
            try
            {
				comm1a.OnMessageReceived += received.MessageReceived;
				comm2.OnMessageReceived += received.MessageReceived;
				comm1b.OnMessageReceived += received.MessageReceived;
				comm1c.OnMessageReceived += received.MessageReceived;
				
                comm1a.Start();
                comm1b.Start();
                comm1c.Start();
                comm2.Start();
                string addr2 = Environment.MachineName.ToLower() + ":" + 8003;

                byte[] testBytes = ser.Serialize(new IntMsg { value = 0, strValue1 = 0.ToString(), strValue2 = "test", msgPartList = new List<MsgPart> { new MsgPart { exValue = new Exception(), strValue = "bla" } } });
                Console.WriteLine("Approximate Message Length: " + testBytes.Length);

               

                int steps = 5000;
                new Thread(new ParameterizedThreadStart(Send)).Start(new SenderInfo
                                                                         {
                                                                             CommService =  comm1a,
                                                                           From = 1,
                                                                             To = steps,
                                                                           ID = 1,
                                                                           RemoteAddr = addr2,
                                                                             Serializer = ser
                                                                         });
                new Thread(new ParameterizedThreadStart(Send)).Start(new SenderInfo
                {
                    CommService = comm1b,
                    From = steps+1,
                    To = steps*2,
                    ID = 2,
                    RemoteAddr = addr2,
                    Serializer = ser
                });
                new Thread(new ParameterizedThreadStart(Send)).Start(new SenderInfo
                {
                    CommService = comm1c,
                    From = steps*2+1,
                    To = steps*3,
                    ID = 3,
                    RemoteAddr = addr2,
                    Serializer = ser
                });
              
                DateTime max = DateTime.Now.AddSeconds(20);
                while (DateTime.Now < max)
                {
                    if (received.Counter >= steps * 3)
                    {
                        break;
                    }
                    Thread.Sleep(250);
                }
                Assert.AreEqual(steps*3, received.Counter);

                Thread.Sleep(500);
            }
            catch (Exception ex)
            {
               
                Assert.Fail("ERROR: " + ex);
            }
            finally
            {
                comm1a.Stop();
                comm1b.Stop();
                comm1c.Stop();
                comm2.Stop();
            }

        }
        private void Send(object tmp)
        {
           
            SenderInfo info = tmp as SenderInfo;
            if (info != null)
            {
                byte[] context = new byte[] { 0, 1, 2, 3, 4, 5 };

                for (int i = info.From; i <= info.To; i++)
                {
                    //comm1.SendMessage(new IntMsg { RemoteAddress = addr2, IntValue = i });
                    byte[] bytes =
                        info.Serializer.Serialize(new IntMsg
                                                      {
                                                          value = i,
                                                          strValue1 = i.ToString(),
                                                          strValue2 = "test:" + info.ID,
                                                          msgPartList =
                                                              new List<MsgPart>
                                                                  {
                                                                      new MsgPart
                                                                          {exValue = new Exception(), strValue = "bla"}
                                                                  }
                                                      });

                    info.CommService.Send(new XcoMessage
                                              {
                                                  //RemoteAddress = info.RemoteAddr,
                                                  Content = bytes,
                                                  CausalityContext = context
                                              }, info.RemoteAddr);
                }
            }

        }



	}
}
